using System;
using System.Threading;
using RxHeat.Common;

namespace RxHeat.Tracing
{
    /// <summary>
    ///     Immutable type to transfer trace details to any custom <see cref="IRxHeatTraceListner" /> implementation.
    ///     <seealso
    ///         cref="TraceMessageExec" />
    /// </summary>
    public class TraceDetails
    {
        /// <summary>
        ///     Initializes a new instance of the <see cref="TraceDetails" /> class.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="traceMessageExec">The trace message exec.</param>
        public TraceDetails(string key, Func<string> traceMessageExec)
            : this(key, Thread.CurrentThread.ToTraceString(), traceMessageExec)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="TraceDetails" /> class.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="threadInfo">The thread info.</param>
        /// <param name="traceMessageExec">The trace message exec.</param>
        public TraceDetails(string key, string threadInfo, Func<string> traceMessageExec)
            : this(key, threadInfo, null, traceMessageExec)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="TraceDetails" /> class.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="traceMessage">The trace message.</param>
        public TraceDetails(string key, string traceMessage)
            : this(key, Thread.CurrentThread.ToTraceString(), traceMessage)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="TraceDetails" /> class.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="threadInfo">The thread info.</param>
        /// <param name="traceMessage">The trace message.</param>
        public TraceDetails(string key, string threadInfo, string traceMessage)
            : this(key, threadInfo, traceMessage, null)
        {
        }

        /// <summary>
        ///     Prevents a default instance of the <see cref="TraceDetails" /> class from being created.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="threadInfo">The thread info.</param>
        /// <param name="traceMessage">The trace message.</param>
        /// <param name="traceMessageExec">The trace message exec.</param>
        private TraceDetails(string key, string threadInfo, string traceMessage, Func<string> traceMessageExec)
        {
            Key = key;
            TraceMessageExec = traceMessageExec;
            TraceMessage = traceMessage;
            ThreadInfo = threadInfo;
        }

        /// <summary>
        ///     Gets the key.
        /// </summary>
        /// <value>
        ///     The key.
        /// </value>
        public string Key { get; private set; }

        /// <summary>
        ///     Gets the thread info.
        /// </summary>
        /// <value>
        ///     The thread info.
        /// </value>
        public string ThreadInfo { get; private set; }

        /// <summary>
        ///     Gets the trace message.
        /// </summary>
        /// <value>
        ///     The trace message.
        /// </value>
        public string TraceMessage { get; private set; }

        /// <summary>
        ///     Some tracers offer deferred message composing using delegates.
        ///     This could be a significant performance enhancer.
        ///     Use this instead of <see cref="TraceMessage" /> for tracers that support that.
        /// </summary>
        /// <value>
        ///     The trace message exec.
        /// </value>
        public Func<string> TraceMessageExec { get; private set; }

        /// <summary>
        ///     Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        ///     A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return String.Format("Key: {0} | {1} | TraceMessage: {2} | TraceMessageBox:{3}", Key, ThreadInfo,
                                 TraceMessage, TraceMessageExec == null ? "null" : TraceMessageExec());
        }
    }
}